
/* Generated by Interface Builder */

#import "Main.h"
#import <appkit/Text.h>
#import <appkit/Panel.h>
#import <appkit/Window.h>
#import <appkit/ScrollView.h>
#import <appkit/Listener.h>
#import <appkit/Button.h>
#import <appkit/Matrix.h>
#import <appkit/Pasteboard.h>
#import <streams/streams.h>
#import <defaults.h>
#include <sys/file.h>
#include <stdio.h>
#import <libc.h>

#define APPNAME "Notes"

char path[1024] = "";
// The application listener.
id listener;


// Definitions for the default insertion position
#define START 1
#define END 0
// Default insertion position.
int insertPos;


// Has the app been initialized.
int init=0;
// Were we autolaunched?
int justauto=0;
// Should we display the main window?
int shouldshow;
// Have we displayed the main window?
int hasshown = 0;



@implementation Main


/* Intercept termination to write text and defaults.*/
- terminate:sender
{
	[self writeText];
	[self writePrefs];
	return [super terminate:sender];
}

/* If the user logs out, we get these rather than the terminate message.*/
- app:sender powerOffIn:(int)ms andSave:(int)aFlag
{
	[self writeText];
	return self;
}
- powerOff:(NXEvent *)theEvent
{
	[self writeText];
	return self;
}



/* Set self as the services handler.*/
- appDidInit:sender
{
	listener = [NXApp appListener];
	[listener setServicesDelegate:self];
	return self;
}

/* Actual initialization, is called every time the application activates.*/
- doinit
{
	/* Perform initialization only if this is the first time.*/
	if (init==0)
	{
		/* Register defaults.*/
		static NXDefaultsVector Defaults = {
			{"InsertPosition", "START"},
			{"WindowFrame", "360 350 500 250"},
			{"NXAutoLaunch", "NO"},
			{NULL}
			};
		NXRegisterDefaults(APPNAME, Defaults);
		/* Get the defaults and the text.*/
		[self readPrefs];
		[self readText];
		/*
			Decide if we should display the window.
			We don't show if and only if the app has just been autolaunched and the
			text is empty.
		*/
		shouldshow = !(justauto && ([self textlength]==0));
		init++;
	}
	return self;
}




/* The number of characters in the text.*/
- (int)textlength
{
	return [text textLength];
}


- (int)activateSelf:(BOOL)flag
{
	/* Make sure initialization has been performed.*/
	[self doinit];
	/*
		If we're supposed to display the window, and haven't yet done so, then
		display it.
	*/
	if (shouldshow)
		if (!hasshown)
		{
			[window makeKeyAndOrderFront:self];
			hasshown = !hasshown;
		}
	/*
		From now on, we should always bring the window to the front when 
		activated.
	*/
	shouldshow = 1;
	return [super activateSelf:flag];
}




/* From the menu.*/

- quitNoSave:sender
{
	int ok;
	/* If the text has been editted, ask for confirmation, otherwise go ahead.*/
	if ([window isDocEdited])
		ok = NXRunAlertPanel(APPNAME, "Quit without saving text?", "Quit", "Cancel", NULL)==NX_ALERTDEFAULT;
	else
		ok = 1;
	if (ok) [super terminate:sender];
	return self;
}

- save:sender
{
	[self writeText];
	[text becomeFirstResponder];
	[text setSel:0:0];
	return self;
}

- reload:sender
{
	int ok;
	/* If the text has been edited, confirm reload, otherwise go ahead.*/
	if ([window isDocEdited])
		ok = NXRunAlertPanel(APPNAME, "Reload text?\nAny changes will be lost.", "Reload", "Cancel", NULL)==NX_ALERTDEFAULT;
	else
		ok = 1;
	if (ok) [self readText];
	return self;
}

- print:sender
{
	[text printPSCode:sender];
	return self;
}





/* Buttons on the prefs panel.*/
- okPrefs:sender
{
	[self takePrefsFromInterface];
	[NXApp stopModal];
	[prefsPanel orderOut:self];
	return self;
}

- revertPrefs:sender
{
	[self setPrefsInterface];
	return self;
}

- cancelPrefs:sender
{
	[NXApp stopModal];
	[prefsPanel orderOut:self];
	return self;
}

/* Display the prefs panel.*/
- showPrefs:sender
{
	[self setPrefsInterface];
	[NXApp runModalFor:prefsPanel];
	return self;
}

/* Set up the prefs panel according to the current values of the defaults.*/
- setPrefsInterface
{
	[enabledSwitch setState:NXIsServicesMenuItemEnabled("Note") ? 1 : 0];
	[positions selectCellAt:insertPos:0];
	return self;
}

/* Set the new values of the defaults according to the prefs panel.*/
- takePrefsFromInterface
{
	NXSetServicesMenuItemEnabled("Note",[enabledSwitch state]);
	if ([startSwitch state])
		insertPos = START;
	else
		insertPos = END;
	return self;
}




/* Get the defaults.*/
- readPrefs
{
	char	const *def;
	int x,y,h,w;
	NXRect frame;

	/* Location of the text window.*/
	def = NXGetDefaultValue(APPNAME, "WindowFrame");
	sscanf(def, "%i %i %i %i", &x, &y, &w, &h);
	/* Position the window.*/
	frame = (NXRect){{x,y},{w,h}};
	[window placeWindow:&frame];
	
	/* Insertion position.*/
	def = NXGetDefaultValue(APPNAME, "InsertPosition");
	if (strcmp(def, "START")==0)
		insertPos = START;
	else
		insertPos = END;
		
	/* Were we autolaunched?.*/
	def = NXGetDefaultValue(APPNAME, "NXAutoLaunch");
	justauto = strcmp(def, "YES")==0;
	
	return self;
}

/* Read the text from the file in the user's home dir.*/
- readText
{
	int	fd;
	NXStream *st;
	
	// Find the file in the user's home directory.
	sprintf(path, "%s/.Notes", getenv("HOME"));

	fd = open(path, O_RDONLY, 0);
	if (fd >= 0)
	{
		if ((st = NXOpenFile(fd, NX_READONLY)) != 0)
		{
			[text readRichText:st];
			[text sizeToFit];
			NXClose(st);
		}
		close(fd);
	}
	
	/* Adjust interface.*/
	[window setDocEdited:NO];
	[text becomeFirstResponder];
	[text setSel:0:0];
	return self;
}

/* Store the defaults.*/
- writePrefs
{
	int x,y,h,w;
	NXRect	frame;
	char def[100];
	
	NXWriteDefault(APPNAME, "InsertPosition",(insertPos==START)?"START":"END");
	[window getFrame:&frame];
	x = frame.origin.x;
	y = frame.origin.y;
	w = frame.size.width;
	h = frame.size.height;
	sprintf(def, "%i %i %i %i", x,y,w,h);
	NXWriteDefault(APPNAME, "WindowFrame", def);
	return self;
}

/* Write the text into the file in the user's home directory.*/
- writeText
{
	int	fd;
	NXStream	*st;
	
	fd = open(path, O_WRONLY | O_CREAT, 0xfff);
	if (fd >= 0)
	{
		if ((st = NXOpenFile(fd, NX_WRITEONLY)) != 0)
		{
			[text writeRichText:st];
			NXClose(st);
		}
		close(fd);
	}
	[window setDocEdited:NO];
	return self;
}




/* Handle the note service.*/
- note:(id)pb userData:(const char *)udata error:(char **)ermsg
{
	int tlength;
	NXSelPt start,end;

	/* Determine if there is a selection in the text window.*/
	[text getSel:&start:&end];

	/* If there isn't, so set a selection according to preference.*/
	if (start.cp==end.cp || start.cp < 0)
	{
		if (insertPos==START)
		{
			[text setSel:0:0];
			[text replaceSel:"\n"];
			[text setSel:0:0];
		}
		else
		{
			tlength = [text textLength];
			[text setSel:tlength:tlength];
			[text replaceSel:"\n"];
			[text setSel:tlength+1:tlength+1];
		}
	}
	
	/* Now replace the selection with the pasteboard data.*/
	[text readSelectionFromPasteboard:pb];
	return self;
}




/* Set the close button to edited state.*/
- (BOOL)textWillChange:sender
{
	[window setDocEdited:YES];
	return NO;
}


/*
Intercept the outlet initialization to find the text object that is the subview of the scolling text, adn set us self as the text's delegate.
*/
- setScroll:anObject
{
	scroll = anObject;
	text = [scroll docView];
	[text setDelegate:self];
	[self setDelegate:self];
	return self;
}

@end
